/*!
 * \file Omega.cc
 * \brief Définition des méthodes sur Omega
 * \author CARBONNEL Jessie
 * \version 1.0
 * \date 23 février 2013
 */

#include "Omega.h"

#include <iostream>
#include <vector>
#include <set>
#include <math.h>

using namespace std;
	
Omega::Omega(){}

Omega::Omega(const vector<Variable>& v){
	for(int i(0);i<(int)v.size();++i){
		variables.push_back(Variable(v[i]));
	}
}

Omega::~Omega(){
	omega.clear();
}

vector<Variable> Omega::getVariables()const{
	return variables;
}

long int Omega::getSize()const{
	int result(1);
	if((int)variables.size() > 0){
		for(int i(0);i<(int)variables.size();++i){
			result = result * variables[i].getNumberOfValues();
		}
	}
	else result = 0;
	return result;
}

long int Omega::getActualSize()const{
	return (long int)omega.size();
}

void Omega::eraseOutcome(int o){
	// O(log n)
	omega.erase(o);
}

void Omega::generateIndex(){

	int taille((int)variables.size());
	int nov[taille]; // Contient les valeurs max de chaque var
	int tab[taille]; // Compteur
	int totmax(0);

   	for(int i(0);i<taille;++i){ 
		nov[i] = variables[i].getNumberOfValues();
		tab[i] = 0;
		totmax = totmax + (nov[i]-1);
	}

    int tot(0);
    int it(taille-1);
    int j;
	int aux;	
	int val;
	omega.insert(0);

   while(tot != totmax){
        while(tab[it] == (nov[it]-1)){
            tab[it] = 0;
            it = it -1;
        } 
        tab[it] = tab[it] + 1;
        it = taille-1;
        tot = 0;
		val = 0;

        for(int i(0);i<taille;++i){
            tot = tot + tab[i];
			val += tab[i] * pow(10,taille-(i+1));

        }omega.insert(val);
    } 
}

void Omega::showIntension()const{
	cout<<"Intension : "<<endl;
	for(int i(0);i<(int)variables.size();++i){
		cout<<" ";
		cout<<"v"<<i<<" : "; variables[i].show();
	}
	cout<<endl;
}

set<int>* Omega::getOmega(){
	return &omega;
}

void Omega::showExtension()const{
	set<int>::iterator lit (omega.begin()), lend(omega.end()); 
	for(;lit!=lend;++lit)
	{
		generateOutcome(*lit).show();
	}
}

void Omega::clear(){
	omega.clear();
}

Outcome Omega::generateOutcome(long int id)const{
	Outcome o;
	generateOutcome(id,o);
	return o;
}

void Omega::generateOutcome(long int id, Outcome &o)const{
	int val(0);
	int nov = (int)variables.size();

    for(int i=0;i<nov;i++){
		val = id % 10;
		id = id / 10;
		o.addValue(variables[nov-(i+1)].getValue(val));
		val=0;
	}
}

int Omega::getCeterisParibus(int o, Preference p, set<int> c){

	int res = -1;
	string mostPreferred = p.getMostPreferred() ;
	string lessPreferred = p.getLessPreferred() ;
	Outcome oc; generateOutcome(o,oc);
	vector<Outcome> constraintRight;

	for(set<int>::iterator it=c.begin(); it!=c.end(); ++it)
	{
		Outcome o1; generateOutcome(*it, o1);
		constraintRight.push_back(o1);	
	} // On genere les outcomes de la partie droite

	vector<Outcome>::iterator lBegin ;
	// Pour chaque Outcome dans la partie droite
	for( lBegin = constraintRight.begin() ; lBegin != constraintRight.end() ; lBegin++ ){
		// Si elle comprend LP et C
		if(p.getCondition() != ""){
			if( (*lBegin).valide(lessPreferred, p.getCondition()) )
			{
				vector<string> values = oc.getValues() ;

				bool deleteOutcome = true ;

				// On verifie si toutes les autre valeurs sont les memes entre lBegin et oc
				for( int l = 0 ; l < (int)values.size() ; l++ )
				{
					if( values[l] != mostPreferred && values[l] != p.getCondition() )
					{
						if( !((*lBegin).isPresent( values[l] ))  )
						{
							deleteOutcome = false ;
						}
					}
				}
		
				if( deleteOutcome ) {
	
					// w' = lBegin
					res = 0;
					int val;
					int taille( (int)variables.size() );
					for(int i(taille-1);i>=0;i--){
						val = variables[i].isPresent( (*lBegin).getValue(taille-(i+1)) );
					
						res += val * pow(10,taille-(i+1));
						val=0;
					}
				}
			}
		}


		else{
			if( (*lBegin).valide(lessPreferred) )
			{
				vector<string> values = oc.getValues() ;

				bool deleteOutcome = true ;

				// On verifie si toutes les autre valeurs sont les memes entre lBegin et oc
				for( int l = 0 ; l < (int)values.size() ; l++ )
				{
					if( values[l] != mostPreferred )
					{
						if( !((*lBegin).isPresent( values[l] ))  )
						{
							deleteOutcome = false ;
						}
					}
				}
		
				if( deleteOutcome ) {
	
					// w' = lBegin
					res = 0;
					int val;
					int taille( (int)variables.size() );
					for(int i(taille-1);i>=0;i--){
						val = variables[i].isPresent( (*lBegin).getValue(taille-(i+1)) );
					
						res += val * pow(10,taille-(i+1));
						val=0;
					}
				}
			}
		}

	}
	return res;
}

